<?php

declare(strict_types=1);

namespace Modules\DataCheck\Http\Controllers;

use Catch\Exceptions\FailedException;
use Catch\Facade\Admin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Modules\DataCheck\Enums\TaskStateEnum;
use Modules\DataCheck\Exceptions\ParamsException;
use Modules\DataCheck\Jobs\DataCheckJob;
use Modules\DataCheck\Models\DcTask;
use Modules\DataCheck\Services\DataCheckService;
use Modules\DataCheck\Services\TaskProcessService;
use Modules\DataCheck\Services\TaskStopService;
use Pro\Support\Helper;

/**
 * @class DcTaskController
 */
class DataCheckController extends BaseController
{
    /**
     * @param DcTask $model
     */
    public function __construct(protected readonly DcTask $model)
    {
    }

    /**
     * 开启数据核对任务
     * @param Request $request
     * @return array
     */
    public function start(Request $request): array
    {
        $taskId = $request->input(['task_id']);
        if (empty($taskId)) {
            throw new ParamsException('task_id 不能为空');
        }

        $task = $this->model->where('task_id', $taskId)->first();
        if (empty($task)) {
            throw new FailedException('任务不存在');
        }
        //任务状态 1=待核对 2=等待核对中 3=核对中 4=核对完成 5=核对失败 6=停止核对 61=任务停止中
        if ($task->task_state == TaskStateEnum::WAIT_RUNNING->value) {
            throw new FailedException('任务正在核对中，请勿重复操作');
        }
        if ($task->task_state == TaskStateEnum::RUNNING->value) {
            throw new FailedException('任务正在核对中，请勿重复操作');
        }
        if ($task->task_state == TaskStateEnum::COMPLETE->value) {
            throw new FailedException('核对任务已完成');
        }
        if ($task->task_state == TaskStateEnum::TASK_STOPING->value) {
            throw new FailedException('核对任务正在停止中，请稍后再试');
        }
        //任务已停止，说明脚本正在执行,更新为正在执行状态，直接返回成功
        /*if ($task->task_state == TaskStateEnum::STOP->value) {
            $task->update([
                'task_state' => TaskStateEnum::RUNNING->value,
                'updated_at' => time(),
                'updated_uid' => Admin::id(),
            ]);
            return [];
        }*/
        //核对已停止(核对完成) 说明点了停止任务，但是后台任务核对已完成，不需要从新核对
        /*if ($task->task_state == TaskStateEnum::STOP_CHECK_COMPLETE->value) {
            $task->update([
                'task_state' => TaskStateEnum::COMPLETE->value,
                'updated_at' => time(),
                'updated_uid' => Admin::id(),
            ]);
            return [];
        }*/

        $userMaxCheckTaskCount = 3; //同一用户，最多可启动3个任务
        $maxCheckTaskCount = 30;//最多同时只能有30个任务

        //同一个用户，同时只能有3个核对任务
        $userCheckCount = $this->model->where('creator_id', Admin::id())
            ->whereIn('task_state', [TaskStateEnum::WAIT_RUNNING->value, TaskStateEnum::RUNNING->value])
            ->count();
        if ($userCheckCount >= $userMaxCheckTaskCount) {
            throw new FailedException("同一个用户，同时只能有{$userMaxCheckTaskCount}个核对任务");
        }

        //最多同时只能有30个核对任务
        /*$allCheckCount = $this->model->whereIn('task_state', [TaskStateEnum::WAIT_RUNNING->value, TaskStateEnum::RUNNING->value])
            ->count();
        if ($allCheckCount >= $maxCheckTaskCount) {
            throw new FailedException("最多同时只能有{$maxCheckTaskCount}个核对任务,当前核对任务数量为{$allCheckCount}");
        }*/

        try {
            DB::transaction(function () use ($task) {
                $task->update([
                    'task_state' => TaskStateEnum::WAIT_RUNNING->value,
                    'updated_at' => time(),
                    'updated_uid' => Admin::id(),
                    'file_download_url' => '',
                    'task_remark' => '',
                ]);
                DataCheckJob::dispatch($task)->onQueue('data-check');
            });
        } catch (\Exception $exception) {
            $log = [
                'msg' => '开启数据核对任务失败',
                'task_id' => $task->task_id,
                'uid' => Admin::id(),
                'error' => [
                    'msg' => $exception->getMessage(),
                    'file' => $exception->getFile(),
                    'line' => $exception->getLine(),
                ],
            ];

            Log::error(json_encode($log, JSON_UNESCAPED_UNICODE));

            throw new FailedException('开启数据核对任务失败');
        }
        //记录管理员行为
        request()->attributes->set('behavior', [
            'module'     => '数据核对',
            'business'   => '任务管理',
            'operation'  => "开启数据核对任务（任务id：{$taskId}）",
            'related_id' => $task->task_id
        ]);

        return [];
    }

    /**
     * 停止数据核对任务
     * @param Request $request
     * @return array
     */
    public function stop(Request $request): array
    {
        $taskId = $request->input(['task_id']);
        if (empty($taskId)) {
            throw new ParamsException('task_id 不能为空');
        }

        $task = $this->model->where('task_id', $taskId)->first();
        if (empty($task)) {
            throw new FailedException('任务不存在');
        }

        if (in_array($task->task_state, [
            TaskStateEnum::WAIT->value,
            TaskStateEnum::WAIT_RUNNING->value,
            TaskStateEnum::RUNNING->value,
        ])) {
            $task->update([
                'task_state' => TaskStateEnum::TASK_STOPING->value,
                'updated_at' => time(),
                'updated_uid' => Admin::id(),
            ]);
        }
        //记录管理员行为
        request()->attributes->set('behavior', [
            'module'     => '数据核对',
            'business'   => '任务管理',
            'operation'  => "停止数据核查任务（任务id：{$taskId}）",
            'related_id' => $task->task_id
        ]);

        //停止任务标识，停止任务标识，用于任务停止时，停止任务
        TaskStopService::stop($taskId);

        return [];
    }

    /**
     * 获取任务进度
     * @param Request            $request
     * @param TaskProcessService $processService
     * @return array
     */
    public function process(Request $request, TaskProcessService $processService): array
    {
        $taskId = $request->input(['task_id']);
        if (empty($taskId)) {
            throw new ParamsException('task_id 不能为空');
        }

        $task = $this->model->where('task_id', $taskId)->first();
        if (empty($task)) {
            throw new FailedException('任务不存在');
        }

        $downloadUrl = $task->file_download_url;
        if (!empty($downloadUrl) && !str_starts_with($downloadUrl, 'http')) {
            $downloadUrl = asset($downloadUrl);
        }

        if (in_array($task->task_state, [
            TaskStateEnum::STOP->value,
            TaskStateEnum::TASK_STOPING->value,
        ])) {
            $taskStateName = '已停止';
            $task->task_state = TaskStateEnum::STOP->value;
        } else {
            $taskStateName = TaskStateEnum::tryFrom($task->task_state)->message();
        }

        $data = [
            'task_state'      => $task->task_state,
            'task_state_name' => $taskStateName,
            'failure_reason'  => '',
        ];
        if (in_array($task->task_state, [TaskStateEnum::COMPLETE->value, TaskStateEnum::FAILED->value])) {
            $data['process'] = 100;
            if($task->task_state == TaskStateEnum::FAILED->value){
                $taskRemark = Helper::jsonToArray($task->task_remark);
                $data['failure_reason'] = $taskRemark['msg']??'-';
            }
        } elseif (in_array($task->task_state, [
            TaskStateEnum::WAIT->value,
            TaskStateEnum::WAIT_RUNNING->value,
            TaskStateEnum::STOP->value,
            TaskStateEnum::TASK_STOPING->value
        ])) {
            $data['process'] = 0;
        } else {
            $data['process'] = $processService->get(DataCheckService::getTaskProcessKey($task->task_id));
        }

        return $data;
    }
}
